package com.nbstar.film.spider.http;

import com.alibaba.fastjson.JSONObject;
import com.nbstar.film.spider.domain.ProxyInfo;
import com.nbstar.film.spider.thread.FilmpProxySingleton;
import com.nbstar.film.spider.thread.ProxyThread;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.helper.HttpConnection;

import javax.net.ssl.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

@Slf4j
public abstract class BaseHttpRequest implements SpiderHttpRequest {

    private HttpResultParserAdaper parserAdaper;
    private Map<String, String> header = new HashMap<>();
    public static final String cookie = "_vwo_uuid_v2=D14B16E4BD1495AD52276CC0A350D9340|594a92c9115db07a712a45a5e7a44abe; douban-fav-remind=1; gr_user_id=3ed2a389-20af-4a48-b85e-de246591f7ca; ll=\"108309\"; bid=EQ1SyATvpxE; __utmv=30149280.16817; __yadk_uid=TQLnEBMLzURvZEbBYtGe8hJctMqHDEyj; __gads=ID=010ef7257a5d70e8:T=1588658626:S=ALNI_MaSHOSUCuNrGC3QUFUW732ikSziaw; dbcl2=\"168178462:DPTfUCxAuyw\"; push_noty_num=0; push_doumail_num=0; douban-profile-remind=1; _ga=GA1.2.510559910.1532074370; ck=poTI; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1595382730%2C%22https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DaNqDnb-2sp2NC829-06O3Qm-4uEy9Xqz1PEXUjM5XQw-BGaYivZMxT3nmeqJL4z9%26wd%3D%26eqid%3Dd9b862ed001a1e03000000065f179bc7%22%5D; __utmc=30149280; __utma=223695111.320804270.1578908758.1595239354.1595382730.12; __utmc=223695111; __utmz=223695111.1595382730.12.11.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; _pk_id.100001.4cf6=9b17b3036f03286d.1578908758.12.1595383392.1595239490.; __utma=30149280.510559910.1532074370.1595382730.1595386012.50; __utmz=30149280.1595386012.50.49.utmcsr=baidu|utmccn=(organic)|utmcmd=organic";
    public static final String useragent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36";
    protected ProxyInfo proxyInfo = null;
    public static final String proxyURL = "http://127.0.0.1:5010/get/";
    public static final String proxyDel = "http://127.0.0.1:5010/delete/?proxy=";
    private String protol = "";
    protected String spiderName = "";

    public String getSpiderName() {
        return spiderName;
    }

    public void setSpiderName(String spiderName) {
        this.spiderName = spiderName;
    }

    //protected BaseSpider spider;

    //public BaseSpider getSpider() {
    //    return spider;
    //}

//    public void setSpider(BaseSpider spider) {
//        this.spider = spider;
//    }

    public String randomAgent() {
        String[] uat_list = {
                "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)",
                "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E) QQBrowser/6.9.11079.201",
                "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 QQBrowser/6.9.11079.201",
                "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E)",
                "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.33 Safari/534.3 SE 2.X MetaSr 1.0",
                "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)",
                "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E)",
                "Mozilla/5.0 (Windows; U; Windows NT 6.1; ) AppleWebKit/534.12 (KHTML, like Gecko) Maxthon/3.0 Safari/534.12",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)",
                "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)",
                "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.0)",
                "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3)",
                "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)",
                "Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
                "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1", "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
                "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
                "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
                "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
                "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
                "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
                "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
                "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
                "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
                "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
                "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
                "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
                "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
                "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36"
        };

        Random rand = new Random();
        return uat_list[rand.nextInt(uat_list.length)];
    }


    public BaseHttpRequest(HttpResultParserAdaper parserAdaper) {
        this.parserAdaper = parserAdaper;
        header.put("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3");
        //header.put("accept-encoding", "gzip, deflate, br");
        header.put("accept-language", "zh-CN,zh;q=0.9");
        header.put("cache-control", "max-age=0");
        header.put("connection", "keep-alive");
        header.put("upgrade-insecure-requests", "1");
        header.put("user-agent", randomAgent());
        header.put("cookie", cookie);
        //String ip = getRomdomIp();
       //header.put("x-forwarded-for", ip);
    }

    public void setProxy(ProxyInfo proxy) {
        this.proxyInfo = proxy;
    }

    public void addHeader(String key, String value) {
        header.put(key, value);
    }

    public void deleteHeader(String key) {
        header.remove(key);
    }

    public void clearHeader( ) {
        header.clear();
    }

    protected String getRomdomIp() {
        String ip = "192.168.";
        Random rand = new Random();
        ip += rand.nextInt(254) + "." + rand.nextInt(254);

        return ip;
    }

    private  void trustAllHttpsCertificates() throws Exception {
        javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
        javax.net.ssl.TrustManager tm = new TrustAnyTrustManager();
        trustAllCerts[0] = tm;
        javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, null);
        javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    @Override
    public HttpURLConnection getConnection(String visitURL) throws Exception {
        HttpURLConnection conn = null;

        URL url = new URL(visitURL);

        if ( protol.equals("https") || (visitURL.contains("https") && protol.isEmpty())) {
            trustAllHttpsCertificates();
            HostnameVerifier hv = new HostnameVerifier() {
                public boolean verify(String urlHostName, SSLSession session) {
                    return true;
                }
            };
            HttpsURLConnection.setDefaultHostnameVerifier(hv);
//            SSLContext sc = SSLContext.getInstance("SSL");
//            sc.init(null, new TrustManager[]{new TrustAnyTrustManager()},
//                    new java.security.SecureRandom());
//            ((HttpsURLConnection)conn).setSSLSocketFactory(sc.getSocketFactory());
//            ((HttpsURLConnection)conn).setHostnameVerifier(new TrustAnyHostnameVerifier());
//
//            conn.setDoOutput(true);
//            conn.setDoInput(true);
//            conn.setUseCaches(false);
        }

        if (proxyInfo != null) {
            URL proxyURL = new URL(proxyInfo.getProxy());
            //设置代理
            InetSocketAddress address = new InetSocketAddress(proxyURL.getHost(),proxyURL.getPort());
            Proxy proxy = new Proxy(Proxy.Type.HTTP, address); // http 代理
            conn = (HttpURLConnection) url.openConnection(proxy);
        } else {
            conn = (HttpURLConnection) url.openConnection();
        }


        for (Map.Entry<String, String> entry : header.entrySet()) {
            conn.setRequestProperty(entry.getKey(), entry.getValue());
        }

        conn.setRequestMethod("GET");
        conn.setReadTimeout(60000);

        return conn;
    }


    public  String sendGet(String url, String param) {
        String result = "";
        BufferedReader in = null;
        try {
            String urlNameString = url;
            if (null != param) {
                urlNameString = url + "?" + param;
            }
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接
            URLConnection connection = realUrl.openConnection();
            // 设置通用的请求属性
            connection.setRequestProperty("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 建立实际的连接
            connection.connect();
            // 获取所有响应头字段
            Map<String, List<String>> map = connection.getHeaderFields();

            in = new BufferedReader(new InputStreamReader(
                    connection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line + "\r\n";
            }
        } catch (Exception e) {
            System.out.println("发送GET请求出现异常！" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输入流
        finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return result;
    }


    public ProxyInfo getProxy() {
//        ProxyInfo proxyInfo = new ProxyInfo();
//        proxyInfo.setProxy("http://localhost:9999");
        ProxyInfo proxyInfo = FilmpProxySingleton.getInstance().getProxy(this.spiderName);

        if (proxyInfo == null) {
            try {
                proxyInfo =  ProxyThread.ipPool.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ;
            log.info("注册代理信息：{},{}",spiderName, proxyInfo);
            FilmpProxySingleton.getInstance().addProxy(spiderName, proxyInfo);
        }
        log.info("获取到代理{}", proxyInfo);
        setProxy(proxyInfo);

        return proxyInfo;
    }

    public void deleteProxy() {
        this.proxyInfo = null;
        ProxyInfo proxyInfo = FilmpProxySingleton.getInstance().getProxy(spiderName);
        if (proxyInfo != null) {
            //proxyInfo = this.proxyInfo;
            FilmpProxySingleton.getInstance().deleteProxy(spiderName);
        }
    }


    public ProxyInfo getProxyInfo() {

//        String json = HttpRequest.sendGet(proxyURL, null);
//        this.proxyInfo = JSONObject.parseObject(json, ProxyInfo.class);

//        try {
//            this.proxyInfo = ProxyThread.ipPool.take();
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        System.out.println(proxyInfo);
       return proxyInfo;
    }

    public byte[] getBin(String url) throws Exception {
        if (parserAdaper instanceof BinParser) {
            BinParser parser = (BinParser) parserAdaper;

            HttpURLConnection connection = (HttpURLConnection) getConnection(url);
            connection.connect();

            byte[] result=  parser.getResult(connection.getInputStream());

            return result;

        }

        return null;
    }

    public void setProtol(String protol) {
        this.protol = protol;
    }

    public String getHtml(String url) throws Exception {
        String html =  "";//parserAdaper.parseResult(connection);

        if (proxyInfo != null) {
            do {
                HttpURLConnection connection = null;
                try {
                    connection = (HttpURLConnection) getConnection(url);
                    connection.connect();

                    html = parserAdaper.parseResult(connection);

                    if (StringUtils.isEmpty(html)) {
                        //删除代理
                        deleteProxy();
                        getProxy();
                    }
                } catch (IOException e) {
                    log.info(proxyInfo.getProxy() + " is unable!" + e.getMessage());
                    deleteProxy();
                    getProxy();

                    //e.printStackTrace();
                } catch (NoSuchAlgorithmException e) {
                    log.info(proxyInfo.getProxy() + " is unable!" + e.getMessage());
                    deleteProxy();
                    getProxy();
                    // e.printStackTrace();
                } catch (KeyManagementException e) {
                    log.info(proxyInfo.getProxy() + " is unable!" + e.getMessage());
                    deleteProxy();
                    getProxy();
                    //e.printStackTrace();
                } finally {
                    connection.disconnect();
                }
            } while (StringUtils.isEmpty(html));

        } else {
            HttpURLConnection connection = (HttpURLConnection) getConnection(url);
            connection.connect();

            html = parserAdaper.parseResult(connection);
            connection.disconnect();
        }


        return html;
    }

    @Override
    public HttpResultParserAdaper getParser() {
        return this.parserAdaper;
    }
}
